package cn.ubest.mvvmcore.base

import android.util.Log
import androidx.lifecycle.*
import cn.ubest.mvvmcore.bean.*
import cn.ubest.mvvmcore.http.HttpCode
import cn.ubest.mvvmcore.http.RetrofitFactory
import cn.ubest.mvvmcore.http.exception.DataCodeException
import cn.ubest.mvvmcore.interfaces.RequestHandler1
import cn.ubest.mvvmcore.interfaces.RequestHandler1Impl
import cn.ubest.mvvmcore.interfaces.RequestHandler2
import cn.ubest.mvvmcore.utils.CoroutineUtils
import cn.ubest.mvvmcore.utils.LogUtils
import cn.ubest.mvvmcore.utils.ToastUtils
import kotlinx.coroutines.*
import java.lang.Exception
import java.lang.reflect.ParameterizedType

/**
 * Created by maoqi on 2020/9/22.
 */
open class BaseViewModel<M : BaseModel> : ViewModel(), LifecycleObserver {
    val mLoadStatusLiveData: MutableLiveData<LoadingState> by lazy { MutableLiveData<LoadingState>() }
    val mOperatingLiveData: MutableLiveData<String> by lazy { MutableLiveData<String>() }
    val mLiveData: MutableLiveData<Any> by lazy { MutableLiveData<Any>() }
    private val mViewModelList by lazy {
        mutableListOf<BaseViewModel<M>>()
    }
    val mModel: M by lazy {
        val parameterizedType = javaClass.genericSuperclass as ParameterizedType
        val cla = parameterizedType.actualTypeArguments[0] as Class<M>
        cla.newInstance()
    }

    companion object {
        const val FINISH_ACTIVITY = "finish_activity"
    }

    /**
     * 如果有多个viewModel,则调用改方法添加到viewModelList中，便于控制生命周期
     */
    fun BaseViewModel<M>.add() {
        mViewModelList.add(this)
    }

    /**
     * ViewModel生命周期的终止
     */
    override fun onCleared() {
        Log.d("BaseViewModel", "${javaClass.simpleName} onCleared")
        super.onCleared()
        //在这里调用viewModelList中的
        mViewModelList.forEach { it.onCleared() }
    }

    /**
     * 解析数据包裹，如果成功则返回data，失败则抛异常
     */
    fun <T> ResultWrapper<T>.resolveWrapper(): T {
        if (code == HttpCode.REQ_SUCCESSFUL && data != null) {
            return data
        } else {
            throw DataCodeException(code, msg)
        }
    }

    /**
     * 解析数据包裹，如果成功则返回data，失败则抛异常
     */
    fun Wrapper.resolveWrapper(): Boolean {
        if (code == HttpCode.REQ_SUCCESSFUL) {
            return true
        } else {
            throw DataCodeException(code, msg)
        }
    }


    /**
     * 列表数据解析数据包裹，如果成功则返回data，失败则抛异常
     */
    fun <T> ListWrapper<T>.resolveWrapper(): MutableList<T> {
        if (code == HttpCode.REQ_SUCCESSFUL && data != null && data.list != null) {
            return data.list
        } else {
            throw DataCodeException(code, msg)
        }
    }

    /**
     * 列表数据解析数据包裹，如果成功则返回data，失败则抛异常
     */
    fun <T> ListDataWrapper<T>.resolveWrapper(): MutableList<T> {
        if (code == HttpCode.REQ_SUCCESSFUL) {
            return data
        } else {
            throw DataCodeException(code, msg)
        }
    }

    /**
     * 请求网络,不处理生命周期，viewmodel clear后依然执行(用于一些后台上报，不参与UI交互的)
     */
    fun <T> request(
        handler: RequestHandler1<T>
    ) {
        CoroutineUtils
            .with()
            .execute {
                requestNetwork({ handler.request1() }, { e -> handler.onError(false, e) })
            }
    }

    /**
     * 请求网络,处理生命周期，viewmodel clear后取消
     */
    fun <T> requestWithLife(
        handler: RequestHandler1<T>,
        isInit: Boolean = false,
        showLoading: Boolean = true
    ) {
        CoroutineUtils
            .with(viewModelScope)
            .executeOnMain {
                if (showLoading) {
                    startLoading(isInit)
                }
                withContext(Dispatchers.IO) {
                    val r = requestNetworkWithLife(
                        { handler.request1() },
                        { e -> handler.onError(isInit, e) })
                    if (r != null) {
                        withContext(Dispatchers.Main) {
                            handler.onSuccess(r)
                        }
                    }
                }
                stopLoading()
            }
    }

    /**
     * 请求网络,处理生命周期，viewmodel clear后取消
     */
    fun <T> requestWithLife(
        isInit: Boolean = false,
        request: suspend () -> T
    ): LiveData<ResultState<T>> {
        return liveData{
            emit(ResultState.Start(isInit))
            try {
                emit(withContext(Dispatchers.IO) {
                    ResultState.Response(request())
                })
            } catch (e: Exception) {
                if (e is DataCodeException) {
                    emit(ResultState.Error(e.code, e.msg))
                } else {
                    emit(ResultState.Error(HttpCode.REQ_LOCAL_ERROR, e.message))
                }
            } finally {
                emit(ResultState.Finally(isInit))
            }
        }
    }

    /**
     * 请求网络,不处理生命周期，viewmodel clear后依然执行(用于一些后台上报，不参与UI交互的)
     */
    fun <T, R> mergeRequest(
        handler: RequestHandler2<T, R>
    ) {
        val coroutine = CoroutineUtils.with()
        coroutine.execute {
            coroutine.merge(it.async(Dispatchers.IO) {
                requestNetwork({
                    handler.request1()
                }, { e ->
                    handler.onError(false, e)
                })
            }, it.async(Dispatchers.IO) {
                requestNetwork({
                    handler.request2()
                }, { e ->
                    handler.onError(false, e)
                })
            }) { t: T?, r: R? ->
                if (t != null && r != null) {
                    handler.onSuccess(t, r)
                }
            }
        }
    }

    /**
     * 并行请求网络,处理生命周期，viewmodel clear后取消
     */
    fun <T, R> mergeRequestWithLife(
        handler: RequestHandler2<T, R>,
        isInit: Boolean = false,
        showLoading: Boolean = true
    ) {
        val coroutine = CoroutineUtils.with(viewModelScope)
        coroutine.executeOnMain {
            if (showLoading) {
                startLoading(isInit)
            }
            val async = it.async(Dispatchers.IO) {
                requestNetworkWithLife({
                    handler.request1()
                }, { e -> handler.onError(isInit, e) })
            }
            val async1 = it.async(Dispatchers.IO) {
                requestNetworkWithLife({
                    handler.request2()
                }, { e -> handler.onError(isInit, e) })
            }
            coroutine.merge(async, async1) { t, r ->
                if (t != null && r != null) {
                    handler.onSuccess(t, r)
                }
            }
            stopLoading()
        }
    }

    /**
     * 网络请求流程,通用的异常处理
     */
    private suspend fun <T> requestNetworkWithLife(
        block: suspend () -> T,
        isInit: Boolean = false
    ): T? {
        return requestNetworkWithLife(block, { e -> handleError(isInit, e) })
    }

    /**
     * 网络请求流程,自己处理异常
     */
    private suspend fun <T> requestNetworkWithLife(
        block: suspend () -> T,
        error: suspend (Exception) -> Unit
    ): T? {
        try {
            //网络请求
            return block()
        } catch (e: Exception) {
            //这里处理请求异常
            LogUtils.d("网络请求报错：${e.message}")
            error(e)
        }
        return null
    }

    /**
     * 网络请求流程
     */
    private suspend fun <T> requestNetwork(
        block: suspend () -> T,
        error: suspend (Exception) -> Unit
    ): T? {
        try {
            //网络请求
            return block()
        } catch (e: Exception) {
            //这里处理请求异常
            LogUtils.d("网络请求报错：${e.message}")
            error(e)
        }
        return null
    }

    /**
     * 默认的错误处理
     */
    fun handleError(isInit: Boolean, e: Exception) {
        if (e is DataCodeException) {
            mLoadStatusLiveData?.postValue(
                LoadingState(
                    State.LOADING_FAILED,
                    isInit,
                    e.code,
                    e.msg
                )
            )
        } else {
            ToastUtils.toast("${e.message}")
        }
    }

    protected fun startLoading(isInit: Boolean) {
        mLoadStatusLiveData.postValue(LoadingState(State.LOADING_START, isInit))
    }

    protected fun stopLoading() {
        mLoadStatusLiveData.postValue(LoadingState(State.LOADING_END))
    }

    protected fun finishActivity() {
        mOperatingLiveData.postValue(FINISH_ACTIVITY)
    }

    protected fun <T> getHandler1(
        request: suspend () -> T,
        onSuccess: (t: T) -> Unit
    ): RequestHandler1<T> {
        return object : RequestHandler1Impl<T>(this) {
            override suspend fun request1(): T {
                return request()
            }

            override fun onSuccess(t: T) {
                onSuccess(t)
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    protected open fun onCreate() {
        Log.d("BaseViewModel", "onCreate")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    protected open fun onStart() {
        Log.d("BaseViewModel", "onStart")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    protected open fun onResume() {
        Log.d("BaseViewModel", "onResume")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    protected open fun onPause() {
        Log.d("BaseViewModel", "onPause")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    protected open fun onStop() {
        Log.d("BaseViewModel", "onStop")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    protected open fun onDestroy() {
        Log.d("BaseViewModel", "onDestroy")
    }
}